home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Info-Mac 3
/
Info_Mac_1994-01.iso
/
Development
/
Information
/
Mac Programming Secrets 1.0.1
/
Chapter 07
/
ZoomRect.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-05-19
|
5KB
|
141 lines
#include "ZoomRect.h"
#include "Math.h" // For pow().
/*******************************************************************************
ZoomRect
Draws a series of rectangles that give the appearance of a source rectangle
being transformed into a destination rectangle. Drawing takes place in a
GrafPort that covers all monitors.
The basic idea is this: a transformation in progress can be said to be
partially complete. The amount by which the transformation is complete can
be expressed as a percentage. Given this percentage, we can calculate the
rectangle that needs to be drawn. For example, if we were animating the
transformation of rectangle (0, 0, 32, 32) into (40, 4, 300, 500),
then rectangle drawn at the 50% point would be (20, 2, 166, 266).
Using mathematical formulas determined by the mode parameter, 12
intermediate percentages are determined, and the rectangles corresponding
to these percentages are generated. These 12 rectangles are then drawn
four at a time. First, rectangles 1, 2, 3, and 4 are drawn. Then,
rectangle 1 is erased and rectangle 5 is drawn. This process continues
until all 12 rectangles have had their turn.
The caller can choose one of three different formulas to determine the
percentages used to generate the rectangles.
kZoomOut - This effect can be used for zooming a small rectangle into
a larger one. Each percentage is 7/5 as large as the
previous percentage. The final generated value is 100%.
This gives the effect of starting out slowly and finishing
up quickly. It can also be percieved as seeing a rectangle
move forward from a far distance.
kZoomIn - This effect can be used for zooming a large rectangle into
a smaller one. Each percentage is 5/7 as large as the
previous percentage. The first value generated is 100%,
and subsequent values are smaller. Because the values are
generated backwards from the way we’d like them, we also
swap the source and destination rectangles to get the
desired effect, which is to start out quickly, and finish
up slowly. It can also be percieved as a rectangle moving
off into the distance.
kLinear - This effect can be used for moving a rectangle from one
place to another without changing its size. Each percentage
is evenly spaced from 0% to 100%. This gives a nice even,
measured effect. It gives the impression of a rectangle
moving in a single plane, rather than moving into the
distance or vice-versa.
*******************************************************************************/
void ZoomRect(Rect source, Rect dest, short mode) {
GrafPtr oldPort;
GrafPort zoomPort;
Rect tempRect[4];
Fixed deltas[4];
int numberOfSteps;
Fixed percentComplete;
Fixed acceleration;
long dasTicks;
GetPort(&oldPort);
OpenPort(&zoomPort);
SetPort(&zoomPort);
CopyRgn(GetGrayRgn(), zoomPort.visRgn);
PenPat(qd.gray);
PenMode(patXor);
numberOfSteps = 12;
switch (mode) {
case kZoomOut:
acceleration = FixRatio(7, 5);
percentComplete = FixRatio(32767/(pow((7./5.), numberOfSteps)), 32767);
break;
case kZoomIn:
tempRect[0] = source;
source = dest;
dest = tempRect[0];
acceleration = FixRatio(5, 7);
percentComplete = 65536; // shorthand for FixRatio(1, 1), or 100%
break;
case kLinear:
acceleration = FixRatio(1, numberOfSteps);
percentComplete = acceleration;
break;
}
deltas[0] = FixRatio(dest.top - source.top, 1);
deltas[1] = FixRatio(dest.left - source.left, 1);
deltas[2] = FixRatio(dest.bottom - source.bottom, 1);
deltas[3] = FixRatio(dest.right - source.right, 1);
SetRect(&tempRect[1], 0, 0, 0, 0);
tempRect[3] = tempRect[2] = tempRect[1];
dasTicks = TickCount() + 1;
do {
tempRect[0] = source;
tempRect[0].top += FixRound(FixMul(deltas[0], percentComplete));
tempRect[0].left += FixRound(FixMul(deltas[1], percentComplete));
tempRect[0].bottom += FixRound(FixMul(deltas[2], percentComplete));
tempRect[0].right += FixRound(FixMul(deltas[3], percentComplete));
FrameRect(&tempRect[0]); // Draw the latest rectangle
while (dasTicks >= TickCount()) ; // Just wait for counter to change
dasTicks = TickCount() + 1;
if (!EmptyRect(&tempRect[3]))
FrameRect(&tempRect[3]); // Erase any guy who’s been around
// too long.
tempRect[3] = tempRect[2];
tempRect[2] = tempRect[1];
tempRect[1] = tempRect[0];
switch (mode) {
case kZoomOut:
case kZoomIn:
percentComplete = FixMul(percentComplete, acceleration);
break;
case kLinear:
percentComplete += acceleration;
break;
}
} while (--numberOfSteps);
FrameRect(&tempRect[3]); // Erase anything left on screen
FrameRect(&tempRect[2]);
FrameRect(&tempRect[1]);
SetPort(oldPort);
ClosePort(&zoomPort);
}